package com.jcfk.system.service;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.jcfk.common.business.service.BaseService;
import com.jcfk.common.cache.redis.service.RedisListService;
import com.jcfk.common.core.context.SpringContextUtils;
import com.jcfk.common.core.utils.BeanUtils;
import com.jcfk.common.security.utils.SecurityUtils;
import com.jcfk.common.web.domain.DataPage;
import com.jcfk.system.dao.SysLogDao;
import com.jcfk.system.domain.dto.SysLogDTO;
import com.jcfk.system.domain.dto.SysRoleDTO;
import com.jcfk.system.domain.dto.SysSimpleLogDTO;
import com.jcfk.system.domain.dto.SysUserDTO;
import com.jcfk.system.domain.po.SysLog;
import com.jcfk.system.domain.po.SysRole;
import com.jcfk.system.domain.po.SysUser;
import com.jcfk.system.domain.query.SysLogQuery;
import com.jcfk.system.domain.query.SysUserQuery;
import com.plumelog.core.dto.RunLogMessage;
import cn.hutool.json.JSONUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 系统操作日志 服务
 */
@Slf4j
@Service
public class SysOperateLogService extends BaseService<SysLogDao, SysLog> {

    /**
     * 缓存服务
     */
    @Autowired
    private RedisListService redisListService;

    private ExecutorService executorService = Executors.newFixedThreadPool(3);


    /**
     * Redis 缓存键名
     */
    private static final String redisKeyName = "plume_operate_log_list";

    /**
     * 是否正在运行
     */
    private Boolean running = false;

    /**
     * 根据条件获取操作日志分页列表
     *
     * @param page  分页设置
     * @param query 查询条件
     * @return 分页查询结果
     */
    public DataPage<SysLogDTO> queryByPage(DataPage<SysLogDTO> page, SysLogQuery query) {
        if (StrUtil.isNotEmpty(query.getModular())) {
            query.setModular("%" + query.getModular() + "%");
        }
        if (StrUtil.isNotEmpty(query.getBusinessType())) {
            query.setBusinessType("%" + query.getBusinessType() + "%");
        }
        if (StrUtil.isNotEmpty(query.getUrl())) {
            query.setBusinessType("%" + query.getBusinessType() + "%");
        }
        if (StrUtil.isNotEmpty(query.getCreatedUserName())) {
            query.setCreatedUserName("%" + query.getCreatedUserName() + "%");
        }
        // 分页查询
        page = this.baseMapper.queryByPage(page, query);
        return page;
    }

    /**
     * 根据主键获取操作日志信息
     *
     * @param id 主键
     * @return StandardCodeDTO
     */
    public SysLogDTO get(String id) {
        // 查询数据
        SysLog item = this.baseMapper.selectById(id);
        SysLogDTO dto = new SysLogDTO();
        try {
            BeanUtils.copyProperties(item, dto);
        } catch (RuntimeException e) {
            throw e;
        }

        return dto;
    }

    /**
     * 启动服务监听
     */
    @PostConstruct
    public void startListen() {
        this.running = true;
        Runnable listenTask = new Runnable() {
            @SneakyThrows
            @Override
            public void run() {
                SysOperateLogService logService = SpringContextUtils.getBean(SysOperateLogService.class);
                while (running) {
                    try {
                        Object logValue = redisListService.leftPop(redisKeyName);
                        if (logValue == null){
                            Thread.sleep(1000);
                            continue;
                        }
                        RunLogMessage log = JSONUtil.toBean(logValue.toString(), RunLogMessage.class);
                        logService.record(log);
                        Thread.sleep(100);
                    } catch (Exception e) {
                        log.error(e.getMessage(), e);
                    }
                }
            }
        };

        executorService.submit(listenTask);
    }

    /**
     * 记录日志
     *
     * @param runLogMessage
     */
    public void record(RunLogMessage runLogMessage) {
        if (StrUtil.isEmpty(runLogMessage.getContent())) {
            return;
        }
        if (!JSONUtil.isJson(runLogMessage.getContent())) {
            return;
        }
        Map<String, Object> contentMap = JSONUtil.toBean(runLogMessage.getContent(), Map.class);

        SysLog log = new SysLog();
        log.setLogLevel(runLogMessage.getLogLevel());
        log.setApplicationName(runLogMessage.getAppName());
        log.setServerName(runLogMessage.getServerName());
        log.setClassFunction(runLogMessage.getClassName());
        if (contentMap.containsKey("modular")) {
            log.setModular(contentMap.get("modular").toString());
        }
        if (contentMap.containsKey("businessType")) {
            log.setBusinessType(contentMap.get("businessType").toString());
        }
        if (contentMap.containsKey("info")) {
            log.setBusinessType(contentMap.get("info").toString());
        }
        if (contentMap.containsKey("url")) {
            log.setUrl(contentMap.get("url").toString());
        }
        if (contentMap.containsKey("requestMethod")) {
            log.setHttpMethod(contentMap.get("requestMethod").toString());
        }
        if (contentMap.containsKey("clientIp")) {
            log.setClientIp(contentMap.get("clientIp").toString());
        }
        if (contentMap.containsKey("requestBody")) {
            log.setRequestBody(JSONUtil.toJsonStr(contentMap.get("requestBody")));
        }
        if (contentMap.containsKey("responseBody")) {
            log.setResponseBody(JSONUtil.toJsonStr(contentMap.get("responseBody")));
        }
        if (contentMap.containsKey("responseCode")) {
            log.setResponseCode(Integer.parseInt(contentMap.get("responseCode").toString()));
        }
        log.setRequestTime(new Date(runLogMessage.getDtTime()));
        if (contentMap.containsKey("executeTime")) {
            log.setExecutionTime(Long.parseLong(contentMap.get("executeTime").toString()));
        }
        log.setCreateTime(new Date());
        if (contentMap.containsKey("userId")) {
            log.setCreatedUserId(contentMap.get("userId").toString());
        }
        if (contentMap.containsKey("userName")) {
            log.setCreatedUserName(contentMap.get("userName").toString());
        }
        if (StrUtil.isEmpty(log.getCreatedUserId())) {
            log.setCreatedUserId("system");
        }
        if (StrUtil.isEmpty(log.getCreatedUserName())) {
            log.setCreatedUserName("system");
        }
        this.baseMapper.insert(log);
    }

    /**
     * 停止监听
     */
    @PreDestroy
    public void stopListen() {
        this.running = false;
        this.executorService.shutdown();
    }

    /**
     * 添加日志
     *
     * @param dto
     * @return
     */
    public void insert(SysSimpleLogDTO dto) {
        // 实体
        SysLog log = new SysLog();
        BeanUtils.copyProperties(dto, log);
        this.setDefaultValue(log);
        this.baseMapper.insert(log);
    }

    /**
     * 设置添加默认值
     *
     * @param dto 添加对象
     */
    public void setDefaultValue(SysLog log) {
        if (StrUtil.isEmpty(log.getCreatedUserId())) {
            log.setCreatedUserId(SecurityUtils.getUserId());
            log.setCreatedUserName(SecurityUtils.getUserName());
            log.setCreateTime(new Date());
        }
    }
}
